package com.sanri.tools.modules.mock.l7.websocket.chat.repository;

import com.alibaba.fastjson.JSON;
import com.sanri.tools.modules.core.dtos.param.PageParam;
import com.sanri.tools.modules.core.service.file.FileManager;
import com.sanri.tools.modules.mock.l7.websocket.chat.domain.Message;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.NameFileFilter;
import org.apache.commons.io.filefilter.NotFileFilter;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.apache.commons.io.input.ReversedLinesFileReader;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * $datadir
 *   chat
 *     messages[Dir]
 *       $from-$to[Dir] from to 使用数字序排序, 然后拼接
 *           $date-message
 *           lastmessage
 */
@Repository
@Slf4j
public class MessageRepository {

    @Autowired
    private FileManager fileManager;

    /**
     * 消息存储
     * @param message
     */
    public void storageMessage(Message message) throws IOException {
        String serializerMessage = serializerMessage(message);

        String from = message.getFromContactId();
        String to = message.getToContactId();
        long sendTime = message.getSendTime();

        String yyyyMMdd = DateFormatUtils.format(sendTime, "yyyyMMdd");

        // 写入文件
        File file = messageFile(from, to, yyyyMMdd, message.isGroup());
        FileUtils.writeStringToFile(file, serializerMessage+"\n",StandardCharsets.UTF_8, true);

        // 每存储一条消息, 将最后一条消息覆盖
        File chatDir = chatDir(from, to, message.isGroup());
        FileUtils.writeStringToFile(new File(chatDir,"lastmessage"), serializerMessage, StandardCharsets.UTF_8);
    }

    /**
     * 读取最后一条消息
     * @param from
     * @param to
     * @return
     */
    public Message loadLastMessage(String from, String to, boolean group) throws IOException {
        File chatDir = chatDir(from, to, group);
        File lastmessageFile = new File(chatDir, "lastmessage");
        if (lastmessageFile.exists()) {
            String lastmessage = FileUtils.readFileToString(lastmessageFile, StandardCharsets.UTF_8);
            Message message = deSerializerMessage(lastmessage);
            return message;
        }
       return null;
    }

    /**
     * 聊天日期列表
     * @param from
     * @param to
     * @param group
     * @return
     */
    public Set<String> dates(String from, String to, boolean group){
        File dir = chatDir(from, to, group);
        if (!dir.exists()){
            return new HashSet<>();
        }
        String[] list = dir.list();
        Set<String> collect = Arrays.stream(list).collect(Collectors.toSet());
        collect.remove("lastmessage");
        return collect;
    }

    /**
     * 加载某次聊天的消息
     * @param from
     * @param to
     * @param date
     * @param pageParam
     * @param group
     * @return
     */
    public List<Message> loadMessage(String from, String to, String date, PageParam pageParam, boolean group){

        File messageFile = messageFile(from, to, date, group);

        if (!messageFile.exists()){
            log.warn("消息丢失 file: {}",messageFile.getAbsolutePath());
            return new ArrayList<>();
        }
        Integer start = pageParam.getStart();

        List<Message> chatMessages = new ArrayList<>();
        int index = 0;
        try(ReversedLinesFileReader reversedLinesFileReader = new ReversedLinesFileReader(messageFile, StandardCharsets.UTF_8);){
            String line = null;
            do {
                line = reversedLinesFileReader.readLine();
                if (index ++ < start && line != null){
                    continue;
                }

                if (StringUtils.isNotBlank(line)) {
                    Message chatMessage = deSerializerMessage(line);
                    chatMessages.add(chatMessage);
                }
            }while (line != null && chatMessages.size() < pageParam.getPageSize());
        } catch (IOException e) {
            log.error("文件读取失败: {}", messageFile.getAbsolutePath());
        }

        // 因为是倒着读出来的, 所以需要将消息反序
        Collections.reverse(chatMessages);

        return chatMessages;

    }

    /**
     * 反序列化消息
     * @param line
     * @return
     */
    public Message deSerializerMessage(String line){
//        String[] split = StringUtils.split(line, ":");
//        Message chatMessage = new Message();
//        chatMessage.setId(split[0]);
//        chatMessage.setType(split[1]);
//        chatMessage.setSendTime(NumberUtils.toLong(split[2]));
//        chatMessage.setStatus(split[3]);
//        chatMessage.setFromContactId(split[4]);
//        chatMessage.setToContactId(split[5]);
//        chatMessage.setContent(split[6]);
//        return chatMessage;
        return JSON.parseObject(line, Message.class);
    }

    /**
     * 序列化消息
     * @param message
     * @return
     */
    public String serializerMessage(Message message){
//        String type = message.getType();
//        long sendTime = message.getSendTime();
//        String status = message.getStatus();
//        String from = message.getFromContactId();
//        String to = message.getToContactId();
//        String content = message.getContent();
//
//        StringBuffer append = new StringBuffer()
//                .append(message.getId())
//                .append(":").append(type)
//                .append(":").append(sendTime)
//                .append(":").append(status)
//                .append(":").append(from)
//                .append(":").append(to)
//                .append(":").append(content);
//        return append.toString();

        return JSON.toJSONString(message);
    }

    /**
     * 消息文件
     * @param from
     * @param to
     * @param time
     * @param group
     * @return
     */
    public File messageFile(String from, String to, String time, boolean group){
        File dir = chatDir(from, to, group);
        if (StringUtils.isBlank(time)){
            // 如果没有指定 time , 则为找最近的
            Collection<File> files = FileUtils.listFiles(dir, new NotFileFilter(new NameFileFilter("lastmessage")), TrueFileFilter.INSTANCE);
            if (CollectionUtils.isEmpty(files)){
                log.warn("没有聊天文件, 目录: {}",dir.getAbsolutePath());
                String yyyyMMdd = DateFormatUtils.format(new Date(), "yyyyMMdd");
                File file = new File(dir, yyyyMMdd);
                return file;
            }
            if (files.size() == 1){
                return files.iterator().next();
            }

            File max = files.iterator().next();
            for (File file : files) {
                String name = file.getName();
                try {
                    Date maxyyyyMMdd = DateUtils.parseDate(max.getName(), "yyyyMMdd");
                    Date yyyyMMdd = DateUtils.parseDate(name, "yyyyMMdd");
                    if (yyyyMMdd.after(maxyyyyMMdd)){
                        max = file;
                    }
                } catch (ParseException e) {
                    log.error(e.getMessage(),e);
                }
            }

            return max;
        }
//        String yyyyMMdd = DateFormatUtils.format(time, "yyyyMMdd");
        return new File(dir,time);
    }

    public File chatDir(String from, String to, boolean group) {
        String chatName = from.compareTo(to) > 0 ? from+"-"+to : to + "-" + from;
        if (group){
            chatName = to;
        }
        File dir = fileManager.mkDataDir("chat/messages/"+chatName);
        dir.mkdirs();
        return dir;
    }
}
